package com.teamall.framework.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.teamall.core.spring.context.CustomPropertyConfigurer;
import com.teamall.framework.exception.BaseAppException;
import com.teamall.framework.exception.SysRuntimeException;
import com.teamall.framework.log.LogManager;
import com.teamall.framework.util.HttpUtils.HttpMethod;
import com.thoughtworks.xstream.core.util.Base64Encoder;

/**
 * <Description> Http工具类<br>
 */
//@Service("interService")
public class HttpUtils {
	private static final LogManager logger = LogManager.getLogger(HttpUtils.class);
    public enum HttpMethod {
        GET, POST, DELETE, PUT
    }

    private HttpURLConnection urlc = null;

    private String encoding = FrameWorkConstants.UTF_8_ENCODING;

    private HttpMethod method = HttpMethod.GET;

    private int timeout = 3000;

    private Map<String, String> properties = new HashMap<String, String>();

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public void setMethod(HttpMethod method) {
        this.method = method;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    /**
     * 发送请求
     * 
     * @param urlStr
     * @param paramMap
     * @throws Exception
     */
    public void sendRequest(String urlStr, Map<String, Object> paramMap) throws BaseAppException {
    	//增加默认参数
    	paramMap.put("PartnerID", "1");
    	//rsa签名
    	String paramStr = signBackUrlParamStr(paramMap);
    	if(this.method.equals(HttpMethod.GET)){
    		urlStr += "?"+paramStr;
    		paramStr = "";
    	}
    	sendRequest(urlStr, paramStr);
    }
    
    public void sendRequest(String url, String data) throws BaseAppException  {
        byte[] sdata = null;
        try {
        	url = StringUtils.encode(url, encoding);
            sdata = data.getBytes(encoding);
        }
        catch (Throwable e) {
        	logger.info("支付接口调用,参数编码错误:"+e.getMessage());
            throw new SysRuntimeException(e, "HttpUtil发送http请求出现异常："+ e.getMessage());
        }
        sendRequest(url, sdata);
    }
    
    public void sendRequest(String url, byte[] data) throws BaseAppException {
        try {
            if (method.equals(HttpMethod.GET)) {
                StringBuffer param = new StringBuffer();
                int i = 0;
                for (String key : properties.keySet()) {
                    if (i == 0) {
                        param.append("?");
                    }
                    else {
                        param.append("&");
                    }
                    param.append(key).append("=").append(properties.get(key));
                    i++;
                }
                url += param;
            }

            URL u = new URL(url);
            urlc = (HttpURLConnection) u.openConnection();
            urlc.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            urlc.setRequestProperty("contentType", encoding);
            urlc.setReadTimeout(timeout);
            urlc.setRequestMethod(String.valueOf(method));
            urlc.setDoOutput(true);
            urlc.setDoInput(true);
            urlc.setUseCaches(false);

            for (String key : properties.keySet()) {
                urlc.addRequestProperty(key, properties.get(key));
            }

            if (!method.equals(HttpMethod.GET)) {
                urlc.getOutputStream().write(data);
            }
            logger.info("接口调用URL:"+url);
            logger.info("接口调用method:"+urlc.getRequestMethod());
            logger.info("接口调用参数:"+new String(data,encoding));
        }catch (Throwable e) {
            throw new SysRuntimeException(e, "接口调用非业务参数组装错误：" + e.getMessage());
        }

    }

    /**
     * 执行接口调用
     * @return
     */
    public String getResponse() throws BaseAppException {
        byte[] buffer = new byte[0];
        StringBuffer bankXmlBuffer=new StringBuffer();
        InputStream stream;
        if (urlc != null) {
            try {
                urlc.setReadTimeout(timeout);
                
                BufferedReader in=new BufferedReader(new InputStreamReader(urlc.getInputStream(),encoding));
                
                String inputLine;
                while((inputLine=in.readLine())!=null){
                	bankXmlBuffer.append(inputLine);
                }
               String ret = bankXmlBuffer.toString();
               
               
               
//                stream = urlc.getInputStream();
//                int count = timeout / 10;
//                while (true) {
//                    if (count <= 0) {
//                        break;
//                    }
//                    if (stream.available() > 0) {
//                        buffer = new byte[stream.available()];
//                        stream.read(buffer);
//                        while (stream.available() > 0) {
//                            byte[] tmpbuffer = new byte[stream.available()];
//                            stream.read(tmpbuffer);
//                            buffer = ByteUtils.append(buffer, tmpbuffer);
//                        }
//                        break;
//                    }
//                    Thread.sleep(10);
//                    count--;
//                }
//
//                String ret = new String(buffer, encoding);
//                logger.info("调用接口返回结果："+ret);
                return ret;
            }catch (Throwable e) {
            	logger.info("访问接口异常:"+e.getMessage());
            	throw new SysRuntimeException(e, "HttpUtil获取http请求出现异常"+ e.getMessage());
            }
        }
        return "";
    }

    /**
     * 调用接口的总调用方法
     * @param action
     * @param map
     * @param method
     * @return
     * @throws Exception
     */
    public Map excuteHttpVisit(String action,Map map,HttpMethod method) throws BaseAppException{
//    	TInterfacelogPO interLog = new TInterfacelogPO();
    	//接口参数组装准备
    	String url = this.getUrl()+action;
    	this.setMethod(method);
    	sendRequest(url, map);
//    	interLog.setName(action);
//    	interLog.setType("调用接口");
//    	interLog.setUrl(url);
//    	interLog.setMethod(String.valueOf(method));
//    	interLog.setInParam(JsonUtil.toJson(map));
//    	interLog.setStartTime(new Date());
//    	interLog.setIsSuccess("false");
//    	interLog.setRemark("参数准备完成，未执行调用接口");
//    	tInterfacelogService.add(interLog);

    	//执行接口调用
    	String jsonStr ="";
//    	try{
//    		jsonStr = getResponse();
//    		interLog.setOutParam(jsonStr);
//    		interLog.setEndTime(new Date());
//    		interLog.setRemark("接口调用成功");
//    	}catch(Exception e){
//    		interLog.setEndTime(new Date());
//    		interLog.setIsSuccess("false");
//			interLog.setRemark("接口调用异常，"+e.getMessage());
////			tInterfacelogService.update(interLog);
//			throw new BaseAppException("接口调用异常，"+e.getMessage());
//    	}
    	Map resMap = JsonUtil.toMap(jsonStr);
    	if(resMap.containsKey("DataSet")==true){
    		resMap.put("DataSet", JsonUtil.toJson(resMap.get("DataSet")));
    	}
    	String result = "false";
		if(resMap!=null&&resMap.get("Result")!=null){
			result = resMap.get("Result").toString();
    	}
		
		//返回结果处理
//		if("true".equals(result)){
//			if(checkSign(resMap)==false){
//				result="false";
//				logger.info("接口返回后，本地验证签名失败！"+resMap.toString());
//				interLog.setRemark("接口返回后，本地验证签名失败！");
//			}
//			interLog.setIsSuccess(result);
////			tInterfacelogService.update(interLog);
//		}else{
//			logger.info("接口返回Result=false,详细返回参数:"+resMap.toString());
//			interLog.setIsSuccess(result);
//			interLog.setRemark("接口返回错误："+resMap.toString());
////			tInterfacelogService.update(interLog);
////			throw new BaseAppException("调用接口失败");
//		}
		logger.info("========调用接口========end===============================================================");
		
		return resMap;
    }
    
    /**
     * GET方式访问http接口
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public Map getHttpVisit(String url,Map map) throws BaseAppException{
    	return excuteHttpVisit(url,map,HttpMethod.GET);
    }
    /**
     * POST方式访问http接口
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public Map postHttpVisit(String url,Map map) throws BaseAppException{
    	return excuteHttpVisit(url,map,HttpMethod.POST);
    }
    /**
     * PUT方式访问http接口
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public Map putHttpVisit(String url,Map map) throws BaseAppException{
    	return excuteHttpVisit(url,map,HttpMethod.PUT);
    }
    /**
     * DELETE方式访问http接口
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public Map deleteHttpVisit(String url,Map map) throws BaseAppException{
    	return excuteHttpVisit(url,map,HttpMethod.DELETE);
    }
    
    /**
	 * 加签并返回JSON字符串  eg:{"Result":false,"ErrorMessage":"必须的参数为空","ErrorCode":9001,"Timestamp":1448263598}
	 * @param paramMap
	 * @return
	 */
	public String signBackJsonStr(Map paramMap){
		paramMap.put("Timestamp", System.currentTimeMillis()/1000);
    	String resultStr = prepareParam(paramMap);
    	logger.info("加签参数:"+resultStr);
    	String sign = RSASignature.sign(resultStr, RSAEncrypt.DEFAULT_PRIVATE_KEY,encoding);
    	logger.info("加签串:"+sign);
    	paramMap.put("Sign_Type", "RSA");
    	paramMap.put("Sign", sign);
    	logger.info("===================end:被调用接口结束=========================================================");
		return JsonUtil.toJson(paramMap);
	}
	/**
	 * 加签并返回URL参数格式字符串  eg: aa=xx&bb=xx&cc=xx
	 * @param paramMap
	 * @return
	 */
	public String signBackUrlParamStr(Map paramMap){
		paramMap.put("Timestamp", System.currentTimeMillis()/1000);
		paramMap.put("PartnerID", 1);
    	String paramStr = prepareParam(paramMap);
    	String sign = RSASignature.sign(paramStr, RSAEncrypt.DEFAULT_PRIVATE_KEY,encoding);
    	paramStr += "&Sign_Type=RSA&Sign=" + sign;
    	logger.info("接口参数、加签:"+paramStr);
		return paramStr;
	}
    
    /**
	 * 验签 正确ture,错误 false
	 * @param paramMap
	 * @return
	 */
	public Boolean checkSign(Map paramMap) throws BaseAppException{
		logger.info("返回参数："+JsonUtil.toJson(paramMap));
		String Sign = "";
		if(paramMap!=null&&paramMap.get("Sign")!=null){
			Sign = paramMap.get("Sign").toString();
			paramMap.remove("Sign");
		}
		String Sign_Type = "";
		if(paramMap!=null&&paramMap.get("Sign_Type")!=null){
			Sign_Type = paramMap.get("Sign_Type").toString();
			paramMap.remove("Sign_Type");
		}
		boolean isRightSign = false;
		if(!StringUtils.isEmpty(Sign)){
			String paramStr = prepareParam(paramMap);
			logger.info("验签参数："+paramStr);
			logger.info("加签串："+Sign);
			if("RSA".equals(Sign_Type)){
				isRightSign = RSASignature.doCheck(paramStr, Sign, RSAEncrypt.DEFAULT_SERVER_PUBLIC_KEY);
//				isRightSign = RSASignature.doCheck(paramStr, Sign, RSAEncrypt.DEFAULT_PUBLIC_KEY);
			}
		}
		logger.info("验签结果："+isRightSign);
		return isRightSign;
	}
    
    public void addProperties(String key, String value) {
        if (properties.containsKey(key)) {
            properties.remove(key);
        } 
        properties.put(key, value);
    }

    /**
     * Map参数集格式格式化成字符串(根据参数名称按A-Z顺序排序) eg:"abdd=1&abcdd=2&acd=3&ace=4"
     * @param paramMap
     * @return
     */
    public String prepareParam(Map<String, Object> paramMap) {
        StringBuffer sb = new StringBuffer();
        Map<String, Object> sortMap = sortMapByKey(paramMap);
        
        Set set = sortMap.entrySet();
        Iterator i = set.iterator();
        while(i.hasNext()) {
           Map.Entry me = (Map.Entry)i.next();
           sb.append("&"+me.getKey()+"="+me.getValue());
        }
        if(sb!=null){
        	return sb.toString().substring(1);
        }else{
        	return "";
        }
    }

    /**
     * Map进行排序
     * @param paramMap
     * @return
     */
    public static Map<String, Object> sortMapByKey(Map<String, Object> paramMap) {
        if (paramMap == null || paramMap.isEmpty()) {
            return null;
        }
        Map<String, Object> sortMap = new TreeMap<String, Object>();
        sortMap.putAll(paramMap);
        return sortMap;
    }
    
    /**
     * 获取配置参数中的主机和端口名
     * @return
     */
    public String getUrl(){
		String host = (String) CustomPropertyConfigurer.getContextProperty("interface.account.host");
		String port = (String) CustomPropertyConfigurer.getContextProperty("interface.account.port");
		return "http://"+host+":"+port;
	}
    
    /**
     * byte转Base64
     * @param bytes
     * @return
     */
    public String getByteToBase64(byte[] bytes){
    	Base64Encoder encoder = new Base64Encoder();
    	if(bytes==null){
    		return "";
    	}else{
    		return encoder.encode(bytes);
    	}
    }
    
    public byte[] download(String url) {
        byte[] retbuffer = new byte[0];
        try {
            URL u = new URL(url);
            urlc = (HttpURLConnection) u.openConnection();
            urlc.setReadTimeout(timeout);
            InputStream inputStream = urlc.getInputStream();
            Thread.sleep(100);
            while (true) {
                int size = inputStream.available() > 0 ? inputStream.available() : 1024;
                byte[] buffer = new byte[size];
                int ret = inputStream.read(buffer);
                if (ret <= 0) {
                    break;
                }

                if (ret == size) {
                    retbuffer = ByteUtils.append(retbuffer, buffer);
                }
                else {
                    byte[] tmpbuffer = new byte[ret];
                    System.arraycopy(buffer, 0, tmpbuffer, 0, tmpbuffer.length);
                    retbuffer = ByteUtils.append(retbuffer, tmpbuffer);
                }
            }
        }
        catch (Throwable e) {
            throw new SysRuntimeException(e, "HttpUtil下载资源出现异常"+ e.getMessage());
        }
        return retbuffer;
    }
    
    
    public static void main(String[] args) throws Exception {
    	
    	HttpUtils util = new HttpUtils();
    	
    	
    	Map paramMap = new HashMap();
		//解签
		paramMap.put("TradeNo", "12");
		paramMap.put("OutTradeNo", "23");
		paramMap.put("PayStatus", "3434");
		paramMap.put("PartnerID", "1");
    	
		String str = util.signBackUrlParamStr(paramMap);
		System.out.println(str);
		
		
//    	String url = "http://192.168.0.123/teamall_web/branch/tBranch/qryBrAndCpList";
//    	Map map = new HashMap();
//    	map.put("cityId", "101");
//    	util.sendRequest(url, map);
//    	
//    	String resStr = util.getResponse();
//    	System.out.println(resStr);
//    	Map map = new HashMap();
//    	map.put("PartnerID", "1");
//    	map.put("Timestamp", "2");
//    	map.put("AccessToken", "4");
//    	map.put("acd", "3");
//    	
//    	Set set = map.entrySet();
//        // Get an iterator
//        Iterator i = set.iterator();
//        // Display elements
//        while(i.hasNext()) {
//           Map.Entry me = (Map.Entry)i.next();
//           System.out.print(me.getKey() + ": ");
//           System.out.println(me.getValue());
//        }
//    	
    	
    	
//    	System.out.println(util.prepareParam(map));
//    	String a = "AccessToken";
//    	String b = "Timestamp";
//    	String c = "PartnerID";
//    	System.out.println(a.compareTo(""));
//    	System.out.println(a.compareTo(c));
//    	System.out.println(c.compareTo(a));
//    	
//    	List list = new ArrayList();
//    	list.add("a");
//    	list.add("b");
//    	list.add("c");
//    	list.add(0, "d");
//    	System.out.println(list.toString());
    }

}
